package mocks

import (
	"github.com/hyperledger/fabric-chaincode-go/shim"
	"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
	"strings"
)



func NewChaincodeStub() shim.ChaincodeStubInterface {
	var db map[string][]byte = make(map[string][]byte)
	chaincodeStub := &ChaincodeStub{}

	chaincodeStub.GetStateCalls(func(key string) ([]byte, error) {
		return db[key], nil
	})

	chaincodeStub.PutStateCalls(func(key string, value []byte) error {
		db[key] = value
		return nil
	})

	chaincodeStub.GetStateByRangeCalls(func(key1 string, key2 string) (shim.StateQueryIteratorInterface, error) {
		ite := &StateQueryIterator{}

		var keys []string
		for k, _ := range db {
			if key1 == "" && key2 == "" {
				keys = append(keys, k)
			} else if (key1 == "" && key2 != "") && (k <= key2) {
				keys = append(keys, k)
			} else if (key1 != "" && key2 == "") && (k >= key1) {
				keys = append(keys, k)
			} else if k >= key1 && k <= key2 {
				keys = append(keys, k)
			}
		}
		keyIndex := 0
		ite.HasNextCalls(func() bool {
			return keyIndex < len(keys)
		})

		ite.NextCalls(func() (*queryresult.KV, error) {
			kv := &queryresult.KV{}
			kv.Key = keys[keyIndex]
			kv.Value = db[keys[keyIndex]]
			kv.Namespace="mock"
			keyIndex++
			return kv,nil
		})

		return ite, nil
	})

	chaincodeStub.CreateCompositeKeyCalls(func(objType string, args []string) (string, error) {
		var keyB []byte = []byte(objType)
		for _, arg := range args {
			keyB = append(keyB, '-')
			keyB = append(keyB, []byte(arg)...)
		}
		return string(keyB), nil
	})

	chaincodeStub.GetStateByPartialCompositeKeyCalls(func(objType string, args []string) (shim.StateQueryIteratorInterface, error) {
		ite := &StateQueryIterator{}

		var keys []string
		//objType-arg[0]-arg[1]...
		for k, _ := range db {
			if strings.HasPrefix(k, objType) {
				if len(args) == 0 {
					keys = append(keys, k)
				} else {
					ks := strings.Split(k, "-")
					match := true
					for i, arg := range args {
						if arg == "" {
							continue
						}
						if ks[i + 1] != arg {
							match = false
						}
					}
					if match {
						keys = append(keys, k)
					}
				}
			}
		}

		keyIndex := 0
		ite.HasNextCalls(func() bool {
			return keyIndex < len(keys)
		})

		ite.NextCalls(func() (*queryresult.KV, error) {
			kv := &queryresult.KV{}
			kv.Key = keys[keyIndex]
			kv.Value = db[keys[keyIndex]]
			kv.Namespace="mock"
			keyIndex++
			return kv,nil
		})
		return ite, nil
	})

	chaincodeStub.SplitCompositeKeyCalls(func(key string) (string, []string, error) {
		keyArr := strings.Split(key, "-")
		return keyArr[0], keyArr[1:], nil
	})
	//
	return chaincodeStub
}
